﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		UserService.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.Collections.Generic;
using System.Net.Mail;
using Dexter.Core.EventArgs;
using Dexter.Domain.Model;
using Dexter.Domain.Results;
using Dexter.Logger.Contracts;
using Dexter.Repository;
using Dexter.Services;

namespace Dexter.Services.Implementation {
	/// <summary>
	/// 	The implementatio of <see cref = "IUserService" />.
	/// </summary>
	public class UserService : IUserService {
		/// <summary>
		/// 	The logger.
		/// </summary>
		protected ILogger Logger;

		/// <summary>
		/// 	An instance of a concrete implementation of <see cref = "IUserRepository" />
		/// </summary>
		protected IUserRepository UserRepository;

		/// <summary>
		/// An instance of a concrete implementation of <see cref = "IRoleRepository" />
		/// </summary>
		protected IRoleRepository RoleRepository;

		/// <summary>
		/// 	Initializes a new instance of the <see cref = "UserService" /> class.
		/// </summary>
		/// <param name = "logger">The logger.</param>
		/// <param name = "userRepository">The user repository.</param>
		/// <param name="roleRepository">The role repository</param>
		public UserService ( ILogger logger , IUserRepository userRepository, IRoleRepository roleRepository ) {
			Logger = logger;
			UserRepository = userRepository;
			RoleRepository = roleRepository;
		}

		/// <summary>
		/// 	Gets a user with roles fetched by his email.
		/// </summary>
		/// <param name = "email">The email of the user.</param>
		/// <returns>
		/// 	An instane of <see cref = "User" /> or null if the user will not exist.
		/// </returns>
		public virtual User GetUserByEmail ( MailAddress email ) {
			var e = new CancelEventArgsWithOneParameter <MailAddress> ( email );

			UserRetrievingByEmail.Raise ( this , e );

			if ( e.Cancel ) {
				return null;
			}

			User user = UserRepository.GetByEmailWithRoles ( email );

			UserRetrievedByEmail.Raise ( this , new GenericEventArgsWithOneParameter <User , MailAddress> ( user , email ) );

			return user;
		}

		/// <summary>
		/// 	Gets a user with roles fetched by his username.
		/// </summary>
		/// <param name = "username">The username of the user.</param>
		/// <returns>
		/// 	An instane of <see cref = "User" /> or null if the user will not exist.
		/// </returns>
		public virtual User GetUserByUsername ( string username ) {
			var e = new CancelEventArgsWithOneParameter <string> ( username );

			UserRetrievingByUsername.Raise ( this , e );

			if ( e.Cancel ) {
				return null;
			}

			User user = UserRepository.GetByUsernameWithRoles ( username );

			UserRetrievedByUsername.Raise ( this , new GenericEventArgsWithOneParameter <User , string> ( user , username ) );

			return user;
		}

		/// <summary>
		/// 	Gets a user with roles fetched by his key.
		/// </summary>
		/// <param name = "key">The key.</param>
		/// <returns>
		/// 	An instane of <see cref = "User" /> or null if the user will not exist.
		/// </returns>
		public virtual User GetUserByKey ( int key ) {
			var e = new CancelEventArgsWithOneParameter <int> ( key );

			UserRetrievingById.Raise ( this , e );

			if ( e.Cancel ) {
				return null;
			}

			User user = UserRepository.GetByKeyWithRoles ( key );

			UserRetrievedById.Raise ( this , new GenericEventArgsWithOneParameter <User , int> ( user , key ) );

			return user;
		}

		/// <summary>
		/// 	Saves the specified user into the repository.
		/// </summary>
		/// <param name = "item">The item.</param>
		public virtual void Save ( User item ) {
			var e = new CancelEventArgsWithOneParameter <User> ( item );

			UserCreating.Raise ( this , new CancelEventArgsWithOneParameter <User> ( item ) );

			if ( e.Cancel ) {
				return;
			}

			UserRepository.Save ( item );

			UserCreated.Raise ( this , new GenericEventArgs <User> ( item ) );
		}

		public virtual void Save (Role role)
		{
			var e = new CancelEventArgsWithOneParameter<Role>(role);

			RoleCreating.Raise(this, new CancelEventArgsWithOneParameter<Role>(role));

			if (e.Cancel)
			{
				return;
			}

			RoleRepository.Save(role);

			RoleCreated.Raise(this, new GenericEventArgs<Role>(role));
		}

		/// <summary>
		/// 	Updates the specified user into the repository.
		/// </summary>
		/// <param name = "item">The item.</param>
		public virtual void Update ( User item ) {
			var e = new CancelEventArgsWithOneParameter <User> ( item );

			UserUpdating.Raise ( this , new CancelEventArgsWithOneParameter <User> ( item ) );

			if ( e.Cancel ) {
				return;
			}

			UserRepository.Update ( item );

			UserUpdated.Raise ( this , new GenericEventArgs <User> ( item ) );
		}

		/// <summary>
		/// 	Deletes the specified user into the repository.
		/// </summary>
		/// <param name = "item">The item.</param>
		public virtual void Delete ( User item ) {
			var e = new CancelEventArgsWithOneParameter <User> ( item );

			UserDeleting.Raise ( this , new CancelEventArgsWithOneParameter <User> ( item ) );

			if ( e.Cancel ) {
				return;
			}

			UserRepository.Delete ( item );

			UserDeleted.Raise ( this , new GenericEventArgs <User> ( item ) );
		}

		/// <summary>
		/// 	Return the number of users online in the specified window time.
		/// </summary>
		/// <param name = "userIsOnlineTimeWindow">The user is online time window.</param>
		/// <returns>The numbers of users online.</returns>
		/// <exception cref = "ArgumentOutOfRangeException">Will be throw if the 'userIsOnlineTimeWindow' will be lesser than 1.</exception>
		public virtual int GetNumberOfUsersOnline ( int userIsOnlineTimeWindow ) {
			return UserRepository.GetOnlineUsers ( userIsOnlineTimeWindow );
		}

		/// <summary>
		/// 	Retrieve a list of users with all roles fetched.
		/// </summary>
		/// <param name = "pageIndex">Index of the page.</param>
		/// <param name = "pageSize">Size of the page.</param>
		/// <returns>
		/// 	An concrete implementation of <see cref = "IPagedResult{T}" />. The result will never be null.
		/// </returns>
		public virtual IPagedResult <User> GetAllUsers ( int pageIndex , int pageSize ) {
			IPagedResult <User> data = UserRepository.GetListOfUserWithRoles ( pageIndex , pageSize );

			UsersRetrieved.Raise ( this , new GenericEventArgs <IPagedResult <User>> ( data ) );

			return data;
		}

		/// <summary>
		/// 	Retrieve a list of users with all roles fetched where the username match (%usernameToMatch%) with the passed value.
		/// </summary>
		/// <param name = "usernameToMatch">The part of the username.</param>
		/// <param name = "pageIndex">Index of the page.</param>
		/// <param name = "pageSize">Size of the page.</param>
		/// <returns>
		/// 	An concrete implementation of <see cref = "IPagedResult{T}" />. The result will never be null.
		/// </returns>
		public virtual IPagedResult <User> FindUsersByName ( string usernameToMatch , int pageIndex , int pageSize ) {
			IPagedResult <User> data = UserRepository.FindUsersByNameWithRoles ( usernameToMatch , pageIndex , pageSize );

			UsersRetrievedByName.Raise ( this , new GenericEventArgsWithOneParameter <IPagedResult <User> , string> ( data , usernameToMatch ) );

			return data;
		}

		/// <summary>
		/// 	Retrieve a list of users with all roles fetched where the email match (%emailToMatch%) with the passed value.
		/// </summary>
		/// <param name = "emailToMatch">The part of the email.</param>
		/// <param name = "pageIndex">Index of the page.</param>
		/// <param name = "pageSize">Size of the page.</param>
		/// <returns>
		/// 	An concrete implementation of <see cref = "IPagedResult{T}" />. The result will never be null.
		/// </returns>
		public virtual IPagedResult <User> FindUsersByEmail ( string emailToMatch , int pageIndex , int pageSize ) {
			IPagedResult <User> data = UserRepository.FindUsersByEmailWithRoles ( emailToMatch , pageIndex , pageSize );

			UsersRetrievedByEmail.Raise ( this , new GenericEventArgsWithOneParameter <IPagedResult <User> , string> ( data , emailToMatch ) );

			return data;
		}

		/// <summary>
		/// Retrieve a list of <see cref="Role"/> without users fetched.
		/// </summary>
		/// <param name="pageIndex">Index of the page.</param>
		/// <param name="pageSize">Size of the page.</param>
		/// <returns>
		/// An concrete implementation of <see cref="IPagedResult{T}"/>. The result will never be null.
		/// </returns>
		/// <remarks>
		/// Be careful, because the collection of <see cref="Role"/> is not populate, so read this property could cause more queries.
		/// </remarks>
		public virtual IPagedResult <Role> GetAllRoles ( int pageIndex , int pageSize ) {
			return new PagedResult <Role> ( pageIndex , pageSize , new[] {
				new Role ( "Administrator" ) {Id = 1} ,
				new Role ( "Poster" ) {Id = 2} 
			} , 2 );
		}

		public bool RoleExists ( string roleName ) {
			return RoleRepository.RoleExists ( roleName );
		}

		/// <summary>
		/// Gets the users in role.
		/// </summary>
		/// <param name="roleName">Name of the role.</param>
		/// <returns></returns>
		public virtual IEnumerable<User> GetUsersInRole (string roleName)
		{
			return RoleRepository.GetUsersInRole(roleName);
		}

		/// <summary>
		/// 	This event will raise when a list of <see cref = "Role" /> will be retrieved by the implementation of <see cref = "GetAllRoles(int, int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <IPagedResult <Role>>> RolesRetrieved;

		/// <summary>
		/// 	This event will raise when a list of <see cref = "Role" /> will be retrieved by the implementation of <see cref = "GetAllRoles(int, int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <IPagedResult <User>>> UserRetrieved;

		/// <summary>
		/// 	This event will raise when a list of <see cref = "Role" /> will be retrieved by the implementation of <see cref = "GetAllUsers(int, int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <IPagedResult <User>>> UsersRetrieved;

		/// <summary>
		/// 	This event will raise when a list of <see cref = "Role" /> will be retrieved by the implementation of <see cref = "FindUsersByEmail(string, int, int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgsWithOneParameter <IPagedResult <User> , string>> UsersRetrievedByEmail;

		/// <summary>
		/// 	This event will raise when a list of <see cref = "Role" /> will be retrieved by the implementation of <see cref = "FindUsersByName(string, int, int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgsWithOneParameter <IPagedResult <User> , string>> UsersRetrievedByName;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will retrieved by the implementation of <see cref = "GetUserByKey(int)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <int>> UserRetrievingById;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be retrieved by the implementation of <see cref = "GetUserByKey(int)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgsWithOneParameter <User , int>> UserRetrievedById;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will retrieved by the implementation of <see cref = "GetUserByUsername(string)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <string>> UserRetrievingByUsername;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be retrieved by the implementation of <see cref = "GetUserByUsername(string)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgsWithOneParameter <User , string>> UserRetrievedByUsername;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will retrieved by the implementation of <see cref = "GetUserByEmail(MailAddress)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <MailAddress>> UserRetrievingByEmail;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be retrieved by the implementation of <see cref = "GetUserByEmail(MailAddress)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgsWithOneParameter <User , MailAddress>> UserRetrievedByEmail;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will created by the implementation of <see cref = "Save(User)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <User>> UserCreating;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be created by the implementation of <see cref = "Save(User)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <User>> UserCreated;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will updated by the implementation of <see cref = "Update(User)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <User>> UserUpdating;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be updated by the implementation of <see cref = "Update(User)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <User>> UserUpdated;

		/// <summary>
		/// 	This event will raise before a <see cref = "User" /> will deleted by the implementation of <see cref = "Delete(User)" />.
		/// </summary>
		public virtual event EventHandler <CancelEventArgsWithOneParameter <User>> UserDeleting;

		/// <summary>
		/// 	This event will raise when a <see cref = "User" /> will be deleted by the implementation of <see cref = "Delete(User)" />.
		/// </summary>
		public virtual event EventHandler <GenericEventArgs <User>> UserDeleted;

		/// <summary>
		/// 	This event will raise before a <see cref = "Role" /> will created by the implementation of <see cref = "Save(Role)" />.
		/// </summary>
		public virtual event EventHandler<CancelEventArgsWithOneParameter<Role>> RoleCreating;

		/// <summary>
		/// 	This event will raise when a <see cref = "Role" /> will be created by the implementation of <see cref = "Save(Role)" />.
		/// </summary>
		public virtual event EventHandler<GenericEventArgs<Role>> RoleCreated;
	}
}
